﻿/* $RCSFile: SelTree.cs $
 * Apache license v2 2011 by Christian Surieux
 * $Source: ?/ADNCRM.Core/UI/WebControls/SelTree.cs $
 * $log$
 * Revision 6 2010/08/06 19:56:30  christian.surieux
 *   Added Log to All cs files
 */

using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Xml;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Globalization;

using AddonNice.Settings;
using AddonNice.Diagnostics;

using Telerik.Web.UI;

using Trace2    =    System.Diagnostics.Trace;

namespace AddonNice.UI.WebControls
{
    [ToolboxData("<{0}:SelTree runat=server></{0}:SelTree>")]
    public class SelTree : CompositeControl
    {
        RadTreeView TreeView1   =   null;
        RadTreeView TreeView2   =   null;
        string _script          =   string.Empty;


        bool _ClientSide   =   true;
        public bool ClientSide
        {
             get { return _ClientSide; }
             set { _ClientSide  =   value; }
        }

        bool _MultiLevel   =   false;
        public bool MultiLevel
        {
             get { return _MultiLevel; }
             set { _MultiLevel  =   value; }
        }

        Unit _TreeHeight    =   Unit.Empty;
        public Unit TreeHeight
        {
             get { return _TreeHeight; }
             set { _TreeHeight  =   value; }
        }

        Unit _TreeWidth    =   new Unit("48%");
        public Unit TreeWidth
        {
             get { return _TreeWidth; }
             set { _TreeWidth  =   value; }
        }

		public string DataValueField
		{
			get
			{
                object ob   =   ViewState["DataValueField"];
                if ( ob != null )
                    return (string)ob;
                return string.Empty;
			}
			set
			{
				ViewState["DataValueField"] = value;
			}
		}

        public string DataTextField
		{
			get
			{
                object ob   =   ViewState["dataTextField"];
                if ( ob != null )
                    return (string)ob;
                return string.Empty;
			}
			set
			{
				ViewState["dataTextField"] = value;
			}
		}

        public string DataFieldID
		{
			get
			{
                object ob   =   ViewState["dataFieldID"];
                if ( ob != null )
                    return (string)ob;
                return string.Empty;
			}
			set
			{
				ViewState["dataFieldID"] = value;
			}
		}
        
        public string DataFieldParentID
		{
			get
			{
                object ob   =   ViewState["dataFieldParentID"];
                if ( ob != null )
                    return (string)ob;
                return string.Empty;
			}
			set
			{
				ViewState["dataFieldParentID"] = value;
			}
		}
        
        public int MaxDataBindDepth
		{
			get
			{
                return (int)ViewState["maxDataBindDepth"];
			}
			set
			{
				ViewState["maxDataBindDepth"] = value;
			}
		}

        string _SelectedTreeName    =   "Tree2";
        public string SelectedTreeName
        {
             get { return _SelectedTreeName; }
             set { _SelectedTreeName  =   value; }
        }
        
        
        object _DataSource  =   null;
        public object DataSource
        {
             get { return _DataSource; }
             set { _DataSource  =   value; }
        }

        public override void DataBind()
        {
            if (WebControlsTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine("[V]SelTree DataBind BEG.", WebControlsTraceSwitch.Sw.Info);
            OnDataBinding(EventArgs.Empty);
            EnsureChildControls();
            TreeView1.DataSource        =   DataSource;
            TreeView1.DataTextField     =   DataTextField;
            TreeView1.DataValueField    =   DataValueField;
            TreeView1.DataFieldID       =   DataFieldID;
            TreeView1.DataFieldParentID =   DataFieldParentID;
            TreeView1.MaxDataBindDepth  =   MaxDataBindDepth;
            TreeView2.Nodes.Clear();
            DataBindChildren();
            if (WebControlsTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine("[V]SelTree DataBind END.", WebControlsTraceSwitch.Sw.Info);
        }

        protected override HtmlTextWriterTag TagKey
        {
            get
            {
                return HtmlTextWriterTag.Div;
            }
        }
        
        /// <summary>
        /// Ctor
        /// </summary>
        public SelTree()
		{
            if (WebControlsTraceSwitch.Sw.TraceVerbose)
                Trace.WriteLine("[V]SelTree Ctor Called.", WebControlsTraceSwitch.Sw.Info);
        }

        protected virtual string MakeScriptName()
        {
            return string.Format("SelTree_{0}_onNodeDropping", ClientID);
        }

        string MakeScript(string nm)
        {
            if (_script == string.Empty)
            {
                /*
                    function onNodeDropping(sender, args) 
                    {
                        var dest = args.get_destNode();
                        if (dest) 
                        {
                                var clientSide      = ClientSide;
                                var firstTreeView   = $find("<%= {0} %>");
                                var secondTreeView  = $find(\"<%= {0} %>");
                            if (clientSide) 
                            {
                                clientSideEdit(firstTreeView,secondTreeView,args);
                                args.set_cancel(true);
                                return;
                            }
                        }
                    }
                 */
                StringBuilder sb    =   new StringBuilder();
                sb.AppendFormat("function {0}(sender, args)\n{{",MakeScriptName());
                sb.Append("var dest = args.get_destNode();\nif (dest)\n{\n");
                if ( ClientSide )
                        sb.Append("var clientSide = true;\n");
                else    sb.Append("var clientSide = false;\n");
                if ( MultiLevel )
                        sb.Append("var multiLevel = true;\n");
                else    sb.Append("var multiLevel = false;\n");
                sb.AppendFormat("var firstTreeView   = $find('{0}');\n",TreeView1.ClientID);
                sb.AppendFormat("var secondTreeView  = $find('{0}');\n",TreeView2.ClientID);
                sb.Append("if (clientSide)\n{\nclientSideEdit(firstTreeView,secondTreeView,multiLevel,args);\nargs.set_cancel(true);\nreturn;\n}\n}\n}");
                _script             =   sb.ToString();
            }
            return _script;
        }

        void AppendNode(RadTreeNode nd,StringBuilder sb)
        {
            if ( nd.Value == string.Empty )
                    sb.AppendFormat("{0};",nd.Text);
            else    sb.AppendFormat("{0};",nd.Value);
            foreach(RadTreeNode n in nd.Nodes)
                AppendNode(n,sb);
        }

        void SetSelection()
        {
            string selNodes     =   string.Empty;
            object ob           =   ViewState["SelTreeSelectedValue"];
            if (ob != null)
                selNodes        =   (string)ob;
            string[] aNode      =   selNodes.Split(new char[] { ';' },StringSplitOptions.RemoveEmptyEntries);
            RadTreeNode nd2     =   null;
            if (TreeView2.Nodes.Count == 0)
            {
                nd2 = new RadTreeNode(SelectedTreeName);
                TreeView2.Nodes.Add(nd2);
            }
            else nd2 = TreeView2.Nodes[0];
            foreach (string ndtxt in aNode)
            {
                if (ndtxt == string.Empty)
                    continue;
                RadTreeNode nd = TreeView1.FindNodeByValue(ndtxt);
                if (nd != null)
                {
                    nd.Remove();
                    nd2.Nodes.Add(nd);
                }
            }
            for (int i = 0; i < nd2.Nodes.Count; )
            {
                RadTreeNode nd  =   nd2.Nodes[i];
                bool found      =   false;
                foreach (string ndtxt in aNode)
                {
                    if (ndtxt == string.Empty)
                        continue;
                    if (ndtxt == nd.Value)
                    {
                        found = true;
                        i++;
                        break;
                    }
                }
                if (!found)
                    nd.Remove();
            }
        }

        public string SelectedValue
        {
            get
            {
                if (ChildControlsCreated)
                {
                    if (TreeView2.Nodes.Count > 0  )
                    {
                        StringBuilder sb    =   new StringBuilder();
                        foreach (RadTreeNode n in TreeView2.Nodes[0].Nodes)
                            AppendNode(n, sb);
                        string sel          =   sb.ToString();
                        ViewState["SelTreeSelectedValue"] = sel;
                        return sel;
                    }
                }
                object ob   =   ViewState["SelTreeSelectedValue"];
                if ( ob != null )
                    return (string)ob;
                return string.Empty;
            }
            set
            {
                ViewState["SelTreeSelectedValue"] =   value;
                if (ChildControlsCreated)
                {
                    if (TreeView2.Nodes.Count > 0)
                        TreeView2.Nodes.Clear();
                }
            }
        }

        public void LoadContentFile(string file)
        {
            EnsureChildControls();
            TreeView1.LoadContentFile(file);
        }

        protected override void Render(HtmlTextWriter writer)
        {
            if ( WebControlsTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine( "[V]SelTree Render BEG.",WebControlsTraceSwitch.Sw.Info);
            if ( DesignMode )
                EnsureChildControls();
            try
            {
                base.Render(writer);
            }
            catch (Exception ex)
            {
                if ( WebControlsTraceSwitch.Sw.TraceError )
                    Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[E]SelTree Render ex: {0}",ex),WebControlsTraceSwitch.Sw.Info);
                throw;
            }
            if ( WebControlsTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine( "[V]SelTree Render END.",WebControlsTraceSwitch.Sw.Info);
       }


        protected override void CreateChildControls()
        {
            if ( WebControlsTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SelTree CreateChildControls BEG ClientSide: {0}", ClientSide),WebControlsTraceSwitch.Sw.Info);
            ClearChildViewState();
            Controls.Clear();
            Style.Add(HtmlTextWriterStyle.Margin,"5px");// to not have right side under tablesettings right side
            HtmlGenericControl  div1        =   new HtmlGenericControl("div");
            div1.Style.Add( HtmlTextWriterStyle.Width,"48%");
            div1.Style.Add( HtmlTextWriterStyle.Position,"relative");
            div1.Style.Add( "float","left");
            TreeView1                       =   new RadTreeView();
            TreeView1.ID                    =   "TreeView1";
            TreeView1.Height                =   TreeHeight;
            TreeView1.Width                 =   new Unit(100,UnitType.Percentage);

            TreeView1.EnableDragAndDrop     =   true;
            TreeView1.AllowNodeEditing      =   false;
            TreeView1.CausesValidation      =   false;
            TreeView1.CausesValidation      =   false;
            TreeView1.OnClientNodeDropping  =   MakeScriptName();
            div1.Controls.Add(TreeView1);

            HtmlGenericControl  div2        =   new HtmlGenericControl("div");
            div2.Style.Add( HtmlTextWriterStyle.Width,"48%");
            div2.Style.Add( HtmlTextWriterStyle.Position,"relative");
            div2.Style.Add( "float","left");
            TreeView2                       =   new RadTreeView();
            TreeView2.ID                    =   "TreeView2";
            TreeView2.Style.Add(HtmlTextWriterStyle.Overflow,"hidden");
            TreeView2.Height                =   TreeHeight;
            TreeView2.Width                 =   new Unit(100,UnitType.Percentage);
            TreeView2.EnableDragAndDrop     =   true;
            TreeView2.AllowNodeEditing      =   false;
            TreeView2.CausesValidation      =   false;
            TreeView2.OnClientNodeDropping  =   MakeScriptName();
            div2.Controls.Add(TreeView2);
            Controls.Add(div1);
            Controls.Add(div2);
            ChildControlsCreated        =   true;
            if ( WebControlsTraceSwitch.Sw.TraceVerbose )
                Trace2.WriteLine("[V]SelTree CreateChildControls END.",WebControlsTraceSwitch.Sw.Info);
        }

        protected override void OnPreRender(EventArgs e)
        {
            if (WebControlsTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine( string.Format(CultureInfo.InvariantCulture,"[V]SelTree OnPreRender BEG IsPostBack: {0}", Page.IsPostBack), WebControlsTraceSwitch.Sw.Info);
            string nm           =   MakeScriptName();
			Type cs	            =	GetType();
            string gPath        =   Path.ToAbsolute(Config.PortalScriptsPath+"/SelTree.js");
            ((ADNPage)Page).RegisterADNClientScriptBlock(cs, nm, MakeScript(nm), true);
            ((ADNPage)Page).RegisterADNClientScriptInclude("SelTree", gPath);
            SetSelection();
            TreeView1.Height    =   TreeHeight;
            TreeView1.Style.Add(HtmlTextWriterStyle.Overflow,"hidden");
            TreeView2.Height    =   TreeHeight;
            TreeView2.Style.Add(HtmlTextWriterStyle.Overflow,"hidden");
            base.OnPreRender(e);
            if (WebControlsTraceSwitch.Sw.TraceVerbose)
                Trace2.WriteLine("[V]SelTree OnPreRender END.", WebControlsTraceSwitch.Sw.Info);
        }

        protected override void OnInit(EventArgs e)
        {
            EnsureChildControls();
            TreeView1.NodeDrop      +=  new RadTreeViewDragDropEventHandler(TreeView_NodeDrop);
            TreeView1.DataBound     +=  new EventHandler(TreeView_DataBound);
            TreeView2.NodeDrop      +=  new RadTreeViewDragDropEventHandler(TreeView_NodeDrop);
            TreeView2.DataBound     +=  new EventHandler(TreeView_DataBound);
            base.OnInit(e);
        }

        void TreeView_DataBound(object sender, EventArgs e)
        {
           ((RadTreeView)sender).ExpandAllNodes();
         }

        void TreeView_NodeDrop(object sender, RadTreeNodeDragDropEventArgs e)
        {
            RadTreeNode sourceNode                  =   e.SourceDragNode;
            RadTreeNode destNode                    =   e.DestDragNode;
            RadTreeViewDropPosition dropPosition    =   e.DropPosition;

            if (destNode == null)//drag&drop is performed between trees
                return;
            
            RadTreeNode firstNode1  =   TreeView1.Nodes[0];
            if ( destNode == firstNode1 )
                    destNode    = firstNode1.Nodes[0];
            if ( destNode == firstNode1 )
                    destNode    = firstNode1.Nodes[0];
            
            RadTreeNode firstNode2  =   TreeView2.Nodes[0];
            if ( destNode == firstNode2 )
                    destNode    = firstNode2.Nodes[0];
            if (sourceNode.TreeView.SelectedNodes.Count <= 1)
            {
                PerformDragAndDrop(dropPosition, sourceNode, destNode);
            }
            else if (sourceNode.TreeView.SelectedNodes.Count > 1)
            {
                foreach (RadTreeNode node in sourceNode.TreeView.SelectedNodes)
                {
                    PerformDragAndDrop(dropPosition, node, destNode);
                }
            }
            else//dropped node will be a sibling of the destination node
            {
                if (sourceNode.TreeView.SelectedNodes.Count <= 1)
                {

                    if (!sourceNode.IsAncestorOf(destNode))
                    {
                        sourceNode.Owner.Nodes.Remove(sourceNode);
                        destNode.Nodes.Add(sourceNode);
                    }
                }
                else if (sourceNode.TreeView.SelectedNodes.Count > 1)
                {
                    foreach (RadTreeNode node in TreeView1.SelectedNodes)
                    {
                        if (!node.IsAncestorOf(destNode))
                        {
                            node.Owner.Nodes.Remove(node);
                            destNode.Nodes.Add(node);
                        }
                    }
                }
            }

            destNode.Expanded       =   true;
            sourceNode.TreeView.UnselectAllNodes();
        }

        private void PerformDragAndDrop(RadTreeViewDropPosition dropPosition, RadTreeNode sourceNode, RadTreeNode destNode)
        {
            if (sourceNode.Equals(destNode) || sourceNode.IsAncestorOf(destNode))
            {
                return;
            }
            sourceNode.Owner.Nodes.Remove(sourceNode);

            switch (dropPosition)
            {
                case RadTreeViewDropPosition.Over:
                    // child
                    if (MultiLevel)
                    {
                        if (!sourceNode.IsAncestorOf(destNode))
                        {
                            destNode.Nodes.Add(sourceNode);
                        }
                    }
                    else  destNode.InsertAfter(sourceNode);
                    break;

                case RadTreeViewDropPosition.Above:
                    // sibling - above                    
                    destNode.InsertBefore(sourceNode);
                    break;

                case RadTreeViewDropPosition.Below:
                    // sibling - below
                    destNode.InsertAfter(sourceNode);
                    break;
            }
        }

   }
}
